package com.ny.zmb.openapi.controller;

/**
 * createAuthor : Xmw
 * createTime : 2024-6-6 8:41
 */

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mzlion.easyokhttp.HttpClient;
import com.ny.zmb.openapi.config.YsConfig;
import com.ny.zmb.openapi.constant.PHPConstant;
import com.ny.zmb.openapi.entity.PmProductOrder;
import com.ny.zmb.openapi.gMdemo.bean.WxBizContent;
import com.ny.zmb.openapi.mapper.PmProductOrderMapper;
import com.ny.zmb.openapi.util.*;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @description 聚合收交易结果明细查询
 */
@RestController
@CrossOrigin
public class PayWxHd {


    @Resource
    private PmProductOrderMapper pmProductOrderMapper;

    private static final String ALLCHAR = "0123456789ABCDEF";

    /**
     * 发起方商户号 服务商在银盛给自己开设的商户号，即可当作发起方商户号
     * 生产环境需要使用自己的发起发商户号，并找相应的对接人员开通所需要的接口权限，并告知是国密还是RSA
     */
    private static final String CERT_ID = "826513173750017";

    /**
     * 银盛端公钥证书
     * 生产环境需要自行去开放平台上下载银盛公钥证书，也可以找对接人提供
     */

    private String YS_PUBLIC_CER_PATH = new YsConfig().getYsPublicCerPath();

    /**
     * 商户端私钥证书
     * 生产环境需要使用自己生产的私钥证书
     */
    private String MERC_PRIVATE_FILE = new YsConfig().getMercPrivateFile();
    /**
     * 商户端私钥证书密码
     * 生产环境需要使用自己私钥的密码
     */
    private static final String MERC_PRIVATE_FILE_PASSWORD = "197Aa2569";

    /**
     * 请求地址域名
     */
    private static final String HTTP_NET = "https://ysgate.ysepay.com";
    //测试 https://appdev.ysepay.com
    //生产 https://ysgate.ysepay.com

    @RequestMapping("/payWxHd")
    public String payWx(WxBizContent wxBizContent) throws Exception {

        if (wxBizContent.getOrderId() == null) {
            return "订单编号不能为空";
        }

        QueryWrapper<PmProductOrder> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("order_no", wxBizContent.getOrderId());

        PmProductOrder productOrder = pmProductOrderMapper.selectOne(queryWrapper);

        wxBizContent.setShopDate(productOrder.getShopDate());

        return selectOrder(wxBizContent);

    }

    //    微信支付成功后 银盛调用这个接口
    @RequestMapping("/payWxHd2")
    public String payWxHd(WxBizContent wxBizContent) throws Exception {

        try {

            System.out.println(wxBizContent.getOrderId());

            if (wxBizContent.getOrderId() == null) {
                return "订单编号不能为空";
            }

            QueryWrapper<PmProductOrder> queryWrapper = new QueryWrapper<>();

            queryWrapper.eq("order_no", wxBizContent.getOrderId());

            PmProductOrder productOrder = pmProductOrderMapper.selectOne(queryWrapper);

            wxBizContent.setShopDate(productOrder.getShopDate());

            String s = selectOrder(wxBizContent);

            // 使用fastjson将JSON字符串转换为Map
            Map<String, Object> map = JSON.parseObject(s, Map.class);
            Map<String, Object> map2 = JSON.parseObject(map.get("data").toString(), Map.class);

            System.out.println("---------------1");
            System.out.println(map2.get("tradeStatus"));
            if (map2.get("tradeStatus").equals("00")) {
                PmProductOrder pmProductOrder = new PmProductOrder();

                pmProductOrder.setPayStatus("1");

                pmProductOrder.setStatus("1");

                final int update = pmProductOrderMapper.update(pmProductOrder, queryWrapper);
                HttpClient.get(PHPConstant.BASE_URL + "/api/index/wxpayNotify?outOrderNo="+wxBizContent.getOrderId()).execute().asString();
                return "成功" + update;
            }
            return "失败";
        } catch (Exception e) {
            System.out.println(e);
            return "失败";
        }
    }

    public String selectOrder(WxBizContent wxBizContent) throws Exception {

        String HTTP_URL = HTTP_NET + "/openapi/unify/online/trade/order/query";

        /** 1、封装请求参数，bizContent（业务参数，需要加密）和check（需要生成密钥并加密）后面设置值*/
        Map<String, String> reqMap = new HashMap<String, String>();
        //接口方法名，根据接口文档取值
        reqMap.put("method", "unify.online.trade.order.query");
        reqMap.put("timeStamp", getCurrentDateTime("yyyy-MM-dd HH:mm:dd"));
        //固定utf-8
        reqMap.put("charset", "utf-8");
        reqMap.put("reqId", String.valueOf(System.currentTimeMillis()));
        //银盛商户号
        reqMap.put("certId", CERT_ID);//测试环境可用商户号zh_test001
        //reqMap.put("certId", "826584847220016");//826584847220016  生产环境测试可用商户号
        reqMap.put("version", "1.0");

        /** 2、生成对业务参数加密的密钥*/
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 16; i++) {
            sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
        }
        String key = ByteUtil.toHexString(sb.toString());

        /** 3、使用银盛公钥对密钥key进行加密，得到加密的key并设置到请求参数check中。publicFilePath为存放银盛公钥的地址*/
        String check = GMSignUtils.encryptData(YS_PUBLIC_CER_PATH, key);
        reqMap.put("check", check);//加密后的密钥

        /** 4、封装业务参数,具体参数见文档，这里只是举例子*/
        Map<String, Object> bizContentMap = new HashMap<>();
        bizContentMap.put("payeeMercId", CERT_ID);
        bizContentMap.put("orderId", wxBizContent.getOrderId());
        bizContentMap.put("shopDate", wxBizContent.getShopDate());

        JSONObject bizJSONObj = JSONObject.parseObject(JSON.toJSONString(bizContentMap));

        /** 5、使用生成的密钥key对业务参数进行加密，并将加密后的业务参数放入请求参数bizContent中*/
        byte[] bte = AESUtil.encrypt(JSONObject.toJSONBytes(bizJSONObj, SerializerFeature.WriteNullStringAsEmpty), ByteUtil.hexStringToBytes(key));
        String msgBizContent = Base64.encodeBase64String(bte);
        reqMap.put("bizContent", msgBizContent);

        /** 6、将请求参数进行sort排序，生成拼接的字符床，并使用接入方私钥对请求参数进行加签，并将加签的值存入请求参数sign中*/
        //6.1 排序生成拼接字符串
        List<String> keys = new ArrayList<String>(reqMap.keySet());
        Collections.sort(keys);
        StringBuilder sb1 = new StringBuilder();
        for (String k : keys) {
            if ("sign".equals(k)) {
                continue;
            }
            sb1.append(k).append("=");
            sb1.append(reqMap.get(k));
            sb1.append("&");
        }
        if (sb1.length() > 0) {
            sb1.setLength(sb1.length() - 1);
        }
        //6.2使用接入方私钥对排序的请求参数加签，并存放到请求参数里面.privateFilePath:私钥地址，prvatePassword:私钥密钥
        String sign = GMSignUtils.signMsgSM2(MERC_PRIVATE_FILE, MERC_PRIVATE_FILE_PASSWORD, sb1.toString());
        reqMap.put("sign", sign);

        /** 7、发送http请求获取返回结果，请求地址以文档为准*/
        try {
            String result = HttpRequestUtil.getDoPostResponse(HTTP_URL, reqMap, "UTF-8", null, 20 * 1000);
            byte[] res = Base64.decodeBase64(result);
            Map<String, String> resMap = (Map<String, String>) JSONObject.parse(new String(res, "UTF-8"));
            System.out.println("http请求返回的结果为:" + JSONObject.toJSONString(resMap));

            /** 8、对结果进行解密，并使用银盛公钥验签*/
            byte[] srcData = GMSignUtils.getSignDataStr1(resMap).getBytes("UTF-8");
            GMCertInfo verifyCertInfo = GMSignUtils.getVerifyCertInfo(YS_PUBLIC_CER_PATH);
            boolean validateSignResult = GMSignUtils.verifyMsgSignSM2(verifyCertInfo, Base64.decodeBase64(resMap.get("sign")), srcData);

            if (!validateSignResult) {
                System.out.println("验签失败");
                return "验签失败";
            }

            /** 9、针对自己的业务，根据返回的结果的code 和 subCode 做接入方的业务处理*/


            /** 10、使用上面生成的加密密钥key，解密返回的业务参数*/
            byte[] dataEncode = Base64.decodeBase64(resMap.get("businessData"));
            byte[] data = AESUtil.decrypt(dataEncode, ByteUtil.hexStringToBytes(key));
            String businessData = new String(data, "UTF-8");
            System.out.println("返回的业务参数为:" + businessData);

            return businessData;

        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

    /**
     * 格式化当前日期时间字符串
     *
     * @return
     */
    private static String getCurrentDateTime(String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(new Date());
    }
}
